/*******************************************************************************
**
** Copyright (c) 2011 - The OWE Team
**
** This file is part of OWE.
**
** OWE is a free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; version
** version 2.1 of the License.
**
** OWE is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with OWE. If not, see <http://www.gnu.org/licenses/>.
**
*******************************************************************************/

#include <owe/authorelement.h>
#include <owe/contentelement.h>
#include <owe/descriptionelement.h>
#include <owe/featureelement.h>
#include <owe/iconelement.h>
#include <owe/licenseelement.h>
#include <owe/nameelement.h>
#include <owe/node.h>
#include <owe/preferenceelement.h>
#include <owe/ustring.h>
#include <owe/widgetelement.h>

OWE_USE_NAMESPACE

/*!
    \class WidgetElement
    \brief Root of the configuration document.

    \ingroup Configuration

    This is the configuration document main element, and the only Element needed
    at all to have a valid config.xml. It is implemented as described
    <a href="http://www.w3.org/TR/widgets/#widget0">here</a>.
*/

/*!
    \fn UString WidgetElement::id() const

    Returns the widget <a href="http://www.w3.org/TR/widgets/#widget-id">id</a>.
*/

/*!
    \fn UString WidgetElement::version() const

    Returns the widget <a href="http://www.w3.org/TR/widgets/#widget-version">
    version</a>.
*/

/*!
    \fn UString WidgetElement::height() const

    Returns the widget <a href="http://www.w3.org/TR/widgets/#widget-height">
    height</a>.
*/

/*!
    \fn UString WidgetElement::width() const

    Returns the widget <a href="http://www.w3.org/TR/widgets/#widget-width">
    width</a>.
*/

/*!
    \fn UString WidgetElement::viewModes() const

    Returns the supported <a href="http://www.w3.org/TR/widgets/#viewmodes">
    view modes</a>. For more information about view modes, refer to the latest
    view mode feature <a href="http://dev.w3.org/2006/waf/widgets-vmmf/">
    documentation</a>.

    \todo Should validate the view modes and return a list instead of a raw
    UString.
*/

/*!
    \fn const AuthorElement *WidgetElement::author() const

    Returns the widget AuthorElement.
*/

/*!
    \fn const ContentElement *WidgetElement::content() const

    Returns the widget ContentElement.
*/

/*!
    \fn const FeatureElementList WidgetElement::feature() const

    Returns a list of features required by the widget. Some of them are mandatory
    and some not. The widget should be invalidated if a mandatory feature is not
    accessible by any reason (not enough permission, unavailability, etc).
*/

/*!
    \fn const IconElementList *WidgetElement::icon() const

    Returns a list of icons available for the widget.
*/

/*!
    \fn const PreferenceElementList *WidgetElement::preference() const

    Returns a list of preferences set to be used in runtime by the widget.
*/

/*!
    Constructs a new WidgetElement from a given \a node.
*/
WidgetElement::WidgetElement(const Node *node)
    : Element(node, Element::Widget)
    , m_id(node->attribute("id"))
    , m_version(node->attribute("version"))
    , m_height(node->attribute("height"))
    , m_width(node->attribute("width"))
    , m_viewModes(node->attribute("viewmodes"))
    , m_author(0)
    , m_content(0)
{
}

/*!
    Destructs the object releasing all allocated resources.
*/
WidgetElement::~WidgetElement()
{
    std::map<UString, NameElement *>::iterator nameIt;
    std::map<UString, DescriptionElement *>::iterator descriptionIt;
    std::map<UString, FeatureElement *>::iterator featureIt;
    std::map<UString, LicenseElement *>::iterator licenseIt;
    std::map<UString, IconElement *>::iterator iconIt;
    std::map<UString, PreferenceElement *>::iterator preferenceIt;

    for (nameIt = m_name.begin(); nameIt != m_name.end(); nameIt++)
        delete nameIt->second;

    for (descriptionIt = m_description.begin();
            descriptionIt != m_description.end(); descriptionIt++)
        delete descriptionIt->second;

    for (featureIt = m_feature.begin();
            featureIt != m_feature.end(); featureIt++)
        delete featureIt->second;

    for (licenseIt = m_license.begin(); licenseIt != m_license.end(); licenseIt++)
        delete licenseIt->second;

    for (iconIt = m_icon.begin(); iconIt != m_icon.end(); iconIt++)
        delete iconIt->second;

    for (preferenceIt = m_preference.begin(); preferenceIt != m_preference.end(); preferenceIt++)
        delete preferenceIt->second;

    m_name.clear();
    m_description.clear();
    m_feature.clear();
    m_license.clear();
    m_icon.clear();

    delete m_author;
    delete m_content;
}

/*!
    Returns a NameElement based on the \a locale.
*/
const NameElement *WidgetElement::name(const char *locale) const
{
    const std::map<UString, NameElement *>::const_iterator it =
        m_name.find(locale);

    if (it != m_name.end())
        return it->second;

    return 0;
}

bool WidgetElement::addName(NameElement *name)
{
    if (m_name.find(name->lang()) != m_name.end())
        return Element::addChild(name);

    m_name[name->lang()] = name;

    return true;
}

/*!
    Returns a DescriptionElement based on the \a locale.
*/
const DescriptionElement *WidgetElement::description(const char *locale) const
{
    const std::map<UString, DescriptionElement *>::const_iterator it =
        m_description.find(locale);

    if (it != m_description.end())
        return it->second;

    return 0;
}

bool WidgetElement::addDescription(DescriptionElement *description)
{
    if (m_description.find(description->lang()) != m_description.end())
        return Element::addChild(description);

    m_description[description->lang()] = description;

    return true;
}

bool WidgetElement::addAuthor(AuthorElement *author)
{
    if (m_author)
        return Element::addChild(author);

    m_author = author;

    return true;
}

bool WidgetElement::addFeature(FeatureElement *feature)
{
    if (!feature->isValid() || m_feature.find(feature->name()) != m_feature.end())
        return Element::addChild(feature);

    m_feature[feature->name()] = feature;

    return true;
}

/*!
    Returns a LicenseElement based on the \a locale.
*/
const LicenseElement *WidgetElement::license(const char *locale) const
{
    const std::map<UString, LicenseElement *>::const_iterator it =
        m_license.find(locale);

    if (it != m_license.end())
        return it->second;

    return 0;
}

bool WidgetElement::addLicense(LicenseElement *license)
{
    if (m_license.find(license->lang()) != m_license.end())
        return Element::addChild(license);

    m_license[license->lang()] = license;

    return true;
}

bool WidgetElement::addContent(ContentElement *content)
{
    if (!content->isValid() || m_content)
        return Element::addChild(content);

    m_content = content;

    return true;
}

bool WidgetElement::addIcon(IconElement *icon)
{
    if (!icon->isValid() || m_icon.find(icon->src()) != m_icon.end())
        return Element::addChild(icon);

    m_icon[icon->src()] = icon;

    return true;
}

bool WidgetElement::addPreference(PreferenceElement *preference)
{
    if (!preference->isValid() || m_preference.find(preference->name()) != m_preference.end())
        return Element::addChild(preference);

    m_preference[preference->name()] = preference;

    return true;
}

bool WidgetElement::addChild(Element *element)
{
    if (!element)
        return false;

    switch (element->type()) {
    case Element::Name:
        return addName(static_cast<NameElement *>(element));
    case Element::Description:
        return addDescription(static_cast<DescriptionElement *>(element));
    case Element::Author:
        return addAuthor(static_cast<AuthorElement *>(element));
    case Element::Feature:
        return addFeature(static_cast<FeatureElement *>(element));
    case Element::License:
        return addLicense(static_cast<LicenseElement *>(element));
    case Element::Content:
        return addContent(static_cast<ContentElement *>(element));
    case Element::Icon:
        return addIcon(static_cast<IconElement *>(element));
    case Element::Preference:
        return addPreference(static_cast<PreferenceElement *>(element));
    default:
        return Element::addChild(element);
    }
}
